package cn.bearspark.happening.provider.service.impl;

import cn.bearspark.common.util.ConvertBeanUtil;
import cn.bearspark.happening.dto.booklive.CancelReqDTO;
import cn.bearspark.happening.dto.booklive.StateReqDTO;
import cn.bearspark.happening.dto.happening.BookLiveInfo4Publish;
import cn.bearspark.happening.enumeration.booklive.BookedEnum;
import cn.bearspark.happening.enumeration.booklive.CanceledEnum;
import cn.bearspark.happening.provider.dao.buffer.BookLiveHashBuffer;
import cn.bearspark.happening.provider.dao.mapper.BookLiveMapper;
import cn.bearspark.happening.provider.dao.mapper.BookLiveUserMapper;
import cn.bearspark.happening.provider.dao.po.BookLivePO;
import cn.bearspark.happening.provider.service.BookLiveService;
import cn.bearspark.happening.provider.dao.co.BookLiveCO;
import cn.bearspark.happening.provider.service.bo.BookLiveBO;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author f
 */
@Service
public class BookLiveServiceImpl implements BookLiveService {

    private final BookLiveMapper bookLiveMapper;
    private final BookLiveUserMapper bookLiveUserMapper;

    private final BookLiveHashBuffer bookLiveBuffer;

    public BookLiveServiceImpl(BookLiveMapper bookLiveMapper,
                               BookLiveUserMapper bookLiveUserMapper,
                               BookLiveHashBuffer bookLiveBuffer) {
        this.bookLiveMapper = bookLiveMapper;
        this.bookLiveUserMapper = bookLiveUserMapper;
        this.bookLiveBuffer = bookLiveBuffer;
    }

    @Override
    public void publish(BookLiveInfo4Publish bookLiveInfo, long bookLiveId, long anchorId) {
        BookLivePO bookLivePO = ConvertBeanUtil.convert(bookLiveInfo, BookLivePO.class);
        bookLivePO.setBookLiveId(bookLiveId);
        bookLivePO.setAnchorId(anchorId);

        bookLiveMapper.insert(bookLivePO);
    }

    @Override
    public void cancel(CancelReqDTO cancelReqDTO) {
        long bookLiveId = cancelReqDTO.getBookLiveId();

        bookLiveBuffer.clean(bookLiveId);

        bookLiveMapper.updateToCanceled(bookLiveId, cancelReqDTO.getUserId(), CanceledEnum.CANCELED.getCode());
    }

    @Override
    public void state(StateReqDTO stateReqDTO) {
        long userId = stateReqDTO.getUserId();
        long bookLiveId = stateReqDTO.getBookLiveId();
        int booked = stateReqDTO.getBooked();

        // 清除预约直播的数据缓存
        bookLiveBuffer.cleanHot(stateReqDTO.getBookLiveId());

        if (booked == BookedEnum.BOOKED.getCode()) {
            // 如果 booked 是已预约，则
            // 新增数据
            bookLiveUserMapper.insert(userId, bookLiveId);
            // 增加预约人数
            bookLiveMapper.incrBookNum(bookLiveId);
        } else {
            // 如果 booked 是未预约，则
            // 删除数据
            bookLiveUserMapper.delete(userId, bookLiveId);
            // 减少预约人数
            bookLiveMapper.decrBookNum(bookLiveId);
        }
    }

    @Override
    public Map<Long, BookLiveBO> mapBookLiveInfo(List<Long> bookLiveIdList, long userId) {
        Map<Long, BookLiveCO> bookLiveCOMap = bookLiveBuffer.map(bookLiveIdList);

        // 查询该用户是否预定了这些直播
        Set<Long> bookedLiveIdSet = bookLiveUserMapper.getBookedLiveIdSet(userId, bookLiveIdList);

        // 组装业务数据
        Map<Long, BookLiveBO> bookLiveBOMap = new HashMap<>(bookLiveCOMap.size());
        bookLiveCOMap.forEach((bookLiveId, bookLiveCO) -> {
            BookLiveBO bookLiveBO = ConvertBeanUtil.convert(bookLiveCO, BookLiveBO.class);
            bookLiveBO.setBooked(bookedLiveIdSet.contains(bookLiveId) ?
                    BookedEnum.BOOKED.getCode() :
                    BookedEnum.UNBOOKED.getCode());
            bookLiveBOMap.put(bookLiveId, bookLiveBO);
        });
        return bookLiveBOMap;
    }

    @Override
    public BookLiveBO getBookLiveInfo(Long bookLiveId, long userId) {
        if (bookLiveId == null) {
            return null;
        }

        // 查询预约直播的基础信息
        BookLiveCO bookLiveCO = bookLiveBuffer.map(List.of(bookLiveId)).get(bookLiveId);
        BookLiveBO bookLiveBO = ConvertBeanUtil.convert(bookLiveCO, BookLiveBO.class);

        // 查询用户是否预约了这个直播
        bookLiveBO.setBooked(bookLiveUserMapper.count(userId, bookLiveId) == 0 ?
                BookedEnum.UNBOOKED.getCode() :
                BookedEnum.BOOKED.getCode());

        return bookLiveBO;
    }

    @Override
    public void delete(long bookLiveId) {
        // 清理数据库中的数据
        bookLiveMapper.delete(bookLiveId);

        // 清理缓存
        bookLiveBuffer.clean(bookLiveId);
    }
}
